﻿using CJiaBao.Core.Utils;
using Core.Configuration.Api;
using Core.Configuration.Config;
using Core.Configuration.Helper;
using Core.Sdk.Util;
using Core.Sdk.WeiXin;
using Core.Sdk.WeiXin.Domain.pay;
using Core.Sdk.WeiXin.Tool;
using IconYuan.Api.Services;
using IconYuan.Manager.Markets;
using IconYuan.Manager.Orders;
using IconYuan.Manager.Pays;
using IconYuan.Manager.Products;
using IconYuan.Manager.Stores;
using IconYuan.Manager.Users;
using IconYuan.Model.DTO.Orders;
using IconYuan.Model.Entity.Markets;
using IconYuan.Model.Entity.Orders;
using IconYuan.Model.Entity.Pays;
using IconYuan.Model.Entity.Users;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

namespace IconYuan.Api.Controllers.Pays
{

    /// <summary>
    /// 支付操作
    /// </summary>
    public class PayController : ApiBase
    {
        readonly OrderManager orderSvc;
        readonly OrderGoodsManager orderGoodsSvc;
        readonly GoodsManager goodsSvc;
        readonly PayManager paySvc;
        readonly UserManager userSvc;
        readonly UserCouponManager userCouponSvc;
        readonly OauthManager oauthSvc;
        readonly StoreManager storeSvc;
        readonly BalanceLogManager balanceLogSvc;
        readonly GradeLogManager gradeLogSvc;
        readonly UserGradeManager gradeSvc;
        readonly PointLogManager pointLogSvc;
        readonly CouponManager couponSvc;
        public PayController()
        {
            orderSvc = new OrderManager();
            orderGoodsSvc = new OrderGoodsManager();
            goodsSvc = new GoodsManager();
            paySvc = new PayManager();
            userSvc = new UserManager();
            userCouponSvc = new UserCouponManager();
            oauthSvc = new OauthManager();
            storeSvc = new StoreManager();
            balanceLogSvc = new BalanceLogManager();
            gradeSvc = new UserGradeManager();
            gradeLogSvc = new GradeLogManager();
            pointLogSvc = new PointLogManager();
            couponSvc = new CouponManager();
        }

        #region 统一支付入口
        /// <summary>
        /// 统一支付入口,返回微信支付参数
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public PayDto Pay(OrderQueryDto model)
        {
            var order = orderSvc.Get(model.order_id);
            CheckOrder(order);
            if (order.pay_price <= 0)
            {
                PayNotify(order);
                return new PayDto() { payStatus = "success" };
            }

            var payment = paySvc.Get(order.store_id);
            if (payment == null) throw new Exception("未配置微信支付参数");
            var store = storeSvc.Get(order.store_id);
            var oauth = oauthSvc.Get(x => x.user_id == order.user_id);
            var mchKey = payment.mchkey;

            var req = new RequestHandler();
            req.setParameter("body", store.store_name);
            req.setParameter("nonce_str", TenpayUtil.getNoncestr().ToLower());
            req.setParameter("out_trade_no", order.order_no);       //商家订单号
            req.setParameter("total_fee", ((int)(order.pay_price * 100)).ToString());        //商品金额,单位分
            req.setParameter("spbill_create_ip", GetIP());                             //用户的公网ip         
            req.setParameter("trade_type", "JSAPI");
            req.setParameter("notify_url", $"{GlobalConfig.ApiDomain}/pay/paynotify");
            //分账标识
            if (order.is_settled == 0)
                req.setParameter("profit_sharing", "Y");

            //服务商模式
            if (!string.IsNullOrEmpty(payment.provider_appid))
            {
                req.setParameter("appid", payment.provider_appid);
                req.setParameter("mch_id", payment.provider_mchid);
                req.setParameter("sub_mch_id", payment.mchid);
                req.setParameter("sub_appid", payment.appid);
                req.setParameter("sub_openid", oauth.open_id);
                req.setParameter("version", "1.0");
                mchKey = payment.provider_mchkey;
            }
            else
            {
                req.setParameter("appid", payment.appid);
                req.setParameter("mch_id", payment.mchid);
                req.setParameter("openid", oauth.open_id);
            }
            req.setParameter("sign", req.CreateMd5Sign("key", mchKey));

            return WeiXinSdk.Pay(req, mchKey);
        }

        /// <summary>
        /// 统一支付回调
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ContentResult PayNotify()
        {
            var formBody = GetBody();
            WeiXinSdk.Log($"PayNotify：回调\r\n{formBody}");
            try
            {
                var res = new ResponseHandler(formBody);
                var order_no = res.getParameter("out_trade_no");

                //支付成功
                if (WeiXinSdk.IsSuccess(res))
                {
                    var order = orderSvc.Get(x => x.order_no == order_no);
                    if (order == null) throw new Exception("订单不存在");

                    if (order.order_status == 20)
                    {
                        order.transaction_id = res.getParameter("transaction_id");
                        PayNotify(order);
                    }
                }
                else
                {
                    WeiXinSdk.Log($"PayNotify 支付失败：{formBody}");
                }
            }
            catch (Exception e)
            {
                WeiXinSdk.Log($"PayNotify 支付异常：{e.ToString()}");
            }

            return XmlSuccess();
        }
        private void PayNotify(Order order)
        {
            order.order_status = 30;
            if (order.jump == 2)
            {
                Upgrade(order);    //升级VIP
            }
            else
            {
                PayOrder(order);    //购买商品
            }
        }
        private ContentResult XmlSuccess()
        {
            return new ContentResult
            {
                Content = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>",
                ContentType = "application/xml",
                StatusCode = 200
            };
        }
        private void Log(string msg)
        {
            LogHelper.WriteLog("weixin", msg);
        }
        #endregion

        #region 购买商品
        private void PayOrder(Order order)
        {
            var user = userSvc.Get(order.user_id);
            //订单商品
            var goodsList = orderGoodsSvc.GetList(x => x.order_id == order.order_id);
            //扣余额
            UpdateBalance(user, order.balance_money * -1, 20, $"消费,{goodsList[0].goods_name}", order.order_id);
            //更新订单
            UpdateOrder(order);
            //扣除优惠券
            UseCoupon(order);
            //兑换扣积分
            UpdatePoint(user, order.points_num * -1, $"兑换,{goodsList[0].goods_name}");
            //赠送积分
            UpdatePoint(user, order.points_gift, $"消费,{goodsList[0].goods_name}");
            //返佣
            var broResult = AddBrokerage(order, user);
            //更新库存
            UpdateStock(goodsList);
            //未分账的订单微信商户资金
            if (broResult < 0)
            {
                PayServices.FinishProfit(order).GetAwaiter().GetResult();
            }
        }

        private void UpdateOrder(Order order)
        {
            orderSvc.Update(x => new Order { order_status = 30, transaction_id = order.transaction_id, pay_time = DateTime.Now }, y => y.order_id == order.order_id);
        }

        /// <summary>
        /// 更新余额
        /// </summary>
        private void UpdateBalance(User user, decimal amount, int scene, string desc, int order_id)
        {
            Log($"更新余额,用户id:{user.user_id},当前余额:{user.balance},变动数量:{amount}");

            //amount: <0 表示扣款, >0 表示加款
            if (amount == 0) return;

            var payMoney = amount < 0 ? amount * -1 : 0;//累计消费金额
            userSvc.Update(x => new User { balance = user.balance + amount, pay_money = x.pay_money + payMoney }, y => y.user_id == user.user_id);

            balanceLogSvc.Insert(new BalanceLog()
            {
                store_id = user.store_id,
                user_id = user.user_id,
                amount = amount,
                balance = user.balance + amount,
                scene = scene,
                describe = desc,
                order_id = order_id,
                create_time = DateTime.Now
            });
        }

        /// <summary>
        /// 更新商品库存
        /// </summary>
        /// <param name="order"></param>
        private void UpdateStock(List<OrderGoods> goodsList)
        {
            var goodsIds = goodsList.Select(x => x.goods_id);
            foreach (var goods in goodsList)
            {
                goodsSvc.UpdateStock(goods.goods_id, goods.buy_count);
            }
        }

        /// <summary>
        /// 更新积分
        /// </summary>
        /// <param name="points">大于0是送积分,小于0是扣积分</param>
        private void UpdatePoint(User user, int points, string desc)
        {
            Log($"更新积分,用户id:{user.user_id},当前积分:{user.points},变动数量:{points}");
            if (points == 0) return;

            var isSuccess = userSvc.Update(x => new User() { points = user.points + points }, y => y.user_id == user.user_id);
            if (isSuccess)
                pointLogSvc.Insert(new PointLog()
                {
                    store_id = user.store_id,
                    user_id = user.user_id,
                    value = points,
                    points = user.points + points,
                    remark = string.Empty,
                    describe = desc,
                    create_time = DateTime.Now
                });
        }

        /// <summary>
        /// 使用优惠券
        /// </summary>
        private void UseCoupon(Order order)
        {
            Log($"更新优惠券,订单id:{order.order_id},优惠券记录id:{order.coupon_id}");
            if (order.coupon_id <= 0) return;

            userCouponSvc.Update(x => new UserCoupon() { is_use = 1, update_time = DateTime.Now }, y => y.user_coupon_id == order.coupon_id);
        }

        /// <summary>
        /// 订单返佣
        /// </summary>
        private int AddBrokerage(Order order, User user)
        {
            if (user.parent_id <= 0)
            {
                Log($"订单未返佣,用户无上级,订单id:{order.order_id}");
                return 0;
            }
            var gradeList = DtoHelper.GetGradeList();
            var userGrade = gradeList.Find(x => x.grade_id == user.grade_id) ?? new UserGrade();

            // 2024-03-21 用户是金卡时不给上级返佣
            // 2024-06-20 改成金卡不限制
            //if (userGrade.grade_id == 3)
            //{
            //    Log($"订单未返佣,用户是金卡时不给上级返佣,订单id:{order.order_id}");
            //    return 0;
            //}

            var parent = userSvc.Get(user.parent_id) ?? new User();
            //返佣人的等级
            var grade = gradeList.Find(x => x.grade_id == parent.grade_id) ?? new UserGrade();

            //付款人已是任意VIP, 则上级返佣比例降为最低VIP的返佣比例
            if (user.grade_id >= gradeList.First().grade_id)
            {
                grade = gradeList.First() ?? new UserGrade();   //最低级VIP
            }
            else if (user.grade_id == gradeList.Last().grade_id)
            {
                Log($"订单未返佣,用户等级已是最高等级,订单id:{order.order_id}");
                return 0;
            }
            var gradeExt = JsonHelper.ToObject<GradeExt>(grade.ext) ?? new GradeExt();
            var brokerage = Math.Floor(order.pay_price * gradeExt.brokerage_ratio) * 0.01m;
            if (brokerage <= 0)
            {
                Log($"订单未返佣,佣金为0,订单id:{order.order_id}");
                return 0;
            }

            //上级返佣
            bool isSuccess = userSvc.Update(x => new User { brokerage = parent.brokerage + brokerage }, y => y.user_id == parent.user_id);
            if (isSuccess)
            {
                var name = user.mobile.Length >= 8 ?
                    $"{user.mobile.Substring(0, 3)}****{user.mobile.Substring(7)}" : user.user_id.ToString();

                var desc = order.jump == 2 ?
                    $"返佣,{name}升级{grade.name}" : $"返佣,{name}消费{order.pay_price}元";

                balanceLogSvc.Insert(new BalanceLog()
                {
                    store_id = parent.store_id,
                    user_id = parent.user_id,
                    amount = brokerage,
                    balance = parent.brokerage + brokerage,
                    scene = 60,
                    describe = desc,
                    order_id = order.order_id,
                    create_time = DateTime.Now
                });
            }
            Log($"订单已返佣,订单id:{order.order_id},返佣人id:{parent.user_id},返佣等级id:{grade.grade_id},付款人id:{user.user_id},实付金额:{order.pay_price}");
            return 1;
        }

        private void CheckOrder(Order order)
        {
            if (order == null) throw new Exception("订单不存在");
            if (order.order_status != 20) throw new Exception("必须是待支付的订单");

            //验证优惠券
            if (order.coupon_id > 0)
            {
                var coupon = userCouponSvc.Get(order.coupon_id);
                var goods_list = orderGoodsSvc.GetList(x => x.order_id == order.order_id);
                var errMsg = OrdersServices.CheckCoupon(coupon, goods_list);
                if (!string.IsNullOrEmpty(errMsg))
                    throw new Exception(errMsg);
            }
        }
        #endregion

        #region 版本升级

        /// <summary>
        /// 版本升级
        /// </summary>
        private void Upgrade(Order order)
        {
            var user = userSvc.Get(order.user_id);
            //更新订单
            UpdateOrder(order);

            var goods = orderGoodsSvc.Get(x => x.order_id == order.order_id);
            WeiXinSdk.Log($"升级,订单id:{order.order_id},等级id:{goods?.goods_id},余额:{user.balance},积分:{user.points}");

            var grade = gradeSvc.Get(goods.goods_no);   //特殊处理，商品编号就是等级ID
            var gradeExt = JsonHelper.ToObject<GradeExt>(grade.ext);
            var old_grade_id = user.grade_id;
            user.grade_id = grade.grade_id;
            user.expire_time = DateTime.Now.AddDays(grade.days + 1);

            Log($"升级,{JsonHelper.ToJson(user)}");
            userSvc.Update(x => new User { grade_id = grade.grade_id, expire_time = user.expire_time }, y => y.user_id == user.user_id);

            //更新余额
            UpdateBalance(user, gradeExt.balance, 50, $"升级{grade.name}", order.order_id);
            //送积分
            UpdatePoint(user, gradeExt.points, $"升级{grade.name}");
            //送优惠券
            CouponGift(order, gradeExt);
            //返佣
            var broResult = AddBrokerage(order, user);
            //等级记录
            gradeLogSvc.Insert(new GradeLog()
            {
                user_id = user.user_id,
                store_id = user.store_id,
                change_type = 20,
                new_grade_id = grade.grade_id,
                old_grade_id = old_grade_id,
                remark = $"升级{grade.name}",
                ext = string.Empty,
                expire_time = DateTime.Now.AddYears(1),
                create_time = DateTime.Now
            });
            //未分账的订单微信商户资金
            if (broResult < 0)
            {
                PayServices.FinishProfit(order).GetAwaiter().GetResult();
            }
        }

        /// <summary>
        /// 赠送优惠券 2024-03-19更新
        /// </summary>
        private void CouponGift(Order order, GradeExt ext)
        {
            if (string.IsNullOrEmpty(ext.coupon_ids)) return;
            var couponIds = ext.coupon_ids.Split(',').Select(x => Convert.ToInt32(x)).ToArray();

            var couponList = couponSvc.GetByIds(couponIds);
            //已领取的券
            var oldCouponList = userCouponSvc.GetList(x => x.user_id == order.user_id && couponIds.Contains(x.coupon_id));
            var date = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-01"));

            if (date.AddMonths(1).Subtract(DateTime.Now).TotalDays < 5)
                date = date.AddMonths(1);   //不足5天,下个月才开始送券

            //赠送优惠券
            for (int i = 0; i < 6; i++)
            {
                foreach (var coupon in couponList)
                {
                    //重复券的数量
                    var count = oldCouponList.Count(
                        x => x.coupon_id == coupon.coupon_id &&
                        x.start_time.Month == date.Month &&
                        x.start_time.Day == date.Day);

                    //每人每月发2张减5元券,且无门槛券 2024-03-19
                    InsertUserCoupon(order.user_id, coupon, date);
                    InsertUserCoupon(order.user_id, coupon, date);

                }
                date = date.AddMonths(1);  //追加一个月
            }
        }

        ///// <summary>
        ///// 赠送优惠券
        ///// </summary>
        //private void CouponGift(Order order, GradeExt ext)
        //{
        //    if (string.IsNullOrEmpty(ext.coupon_ids)) return;
        //    var couponIds = ext.coupon_ids.Split(',').Select(x => Convert.ToInt32(x)).ToArray();

        //    var couponList = couponSvc.GetByIds(couponIds);
        //    //已领取的券
        //    var oldCouponList = userCouponSvc.GetList(x => x.user_id == order.user_id && couponIds.Contains(x.coupon_id));
        //    var date = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-01"));

        //    if (date.AddMonths(1).Subtract(DateTime.Now).TotalDays < 5)
        //        date = date.AddMonths(1);   //不足5天,下个月才开始送券

        //    //赠送优惠券
        //    for (int i = 0; i < 12; i++)
        //    {
        //        foreach (var coupon in couponList)
        //        {
        //            //重复券的数量
        //            var count = oldCouponList.Count(
        //                x => x.coupon_id == coupon.coupon_id &&
        //                x.start_time.Month == date.Month &&
        //                x.start_time.Day == date.Day);

        //            //减100券每月1张,减10券每月2张,减20每月2张
        //            if (coupon.reduce_price >= 100 && count < 1)
        //            {
        //                InsertUserCoupon(order.user_id, coupon, date);
        //            }
        //            else if (coupon.reduce_price < 100 && count < 2)
        //            {
        //                InsertUserCoupon(order.user_id, coupon, date);
        //                InsertUserCoupon(order.user_id, coupon, date);
        //            }

        //            //偶数月多发一张10元券
        //            if (coupon.reduce_price <= 10 && date.Month % 2 == 0 && count < 3)
        //            {
        //                InsertUserCoupon(order.user_id, coupon, date);
        //            }
        //        }
        //        date = date.AddMonths(1);  //追加一个月
        //    }
        //}

        /// <summary>
        /// 赠送优惠券
        /// </summary>
        void InsertUserCoupon(int user_id, Coupon coupon, DateTime start_time)
        {
            var end_time = coupon.end_time;
            if (coupon.expire_type == 10)
            {
                end_time = start_time.AddDays(coupon.expire_day);
                if (end_time.Month > start_time.Month)
                    end_time = Convert.ToDateTime(start_time.ToString("yyyy-MM-01")).AddMonths(1).AddSeconds(-1);
            }

            userCouponSvc.Insert(new UserCoupon()
            {
                store_id = coupon.store_id,
                user_id = user_id,
                coupon_id = coupon.coupon_id,
                coupon_type = coupon.coupon_type,
                min_price = coupon.min_price,
                reduce_price = coupon.reduce_price,
                name = coupon.name,
                range = coupon.range,
                range_config = coupon.range_config,
                discount = coupon.discount,

                expire_type = coupon.expire_type,
                expire_day = coupon.expire_day,
                start_time = start_time,
                end_time = end_time,
                is_expire = 0,
                is_use = 0,
                create_time = DateTime.Now,
                update_time = DateTime.Now,
            });
        }

        #endregion

        #region 版本升级问题处理

        /// <summary>
        /// 补发升级的余额(每次调用都会补发)
        /// </summary>
        /// <param name="order_id"></param>
        [HttpGet]
        public void SendBalance(int order_id)
        {
            var order = orderSvc.Get(order_id);
            var goods = orderGoodsSvc.Get(x => x.order_id == order.order_id);
            var user = userSvc.Get(order.user_id);

            var grade = gradeSvc.Get(goods.goods_no);   //特殊处理，商品编号就是等级ID
            var gradeExt = JsonHelper.ToObject<GradeExt>(grade.ext);
            //更新余额
            UpdateBalance(user, gradeExt.balance, 50, $"升级{grade.name}", order.order_id);
        }

        /// <summary>
        /// 补发积分(每次调用都会补发)
        /// </summary>
        /// <param name="order_id"></param>
        [HttpGet]
        public void SendPoint(int order_id)
        {
            var order = orderSvc.Get(order_id);
            var goods = orderGoodsSvc.Get(x => x.order_id == order.order_id);
            var user = userSvc.Get(order.user_id);

            var grade = gradeSvc.Get(goods.goods_no);   //特殊处理，商品编号就是等级ID
            var gradeExt = JsonHelper.ToObject<GradeExt>(grade.ext);

            UpdatePoint(user, gradeExt.points, $"升级{grade.name}");
        }

        /// <summary>
        /// 补发优惠券(每次调用会去重)
        /// </summary>
        /// <param name="order_id"></param>
        [HttpGet]
        public void SendCoupon(int order_id)
        {
            var order = orderSvc.Get(order_id);
            var goods = orderGoodsSvc.Get(x => x.order_id == order.order_id);

            var grade = gradeSvc.Get(goods.goods_no);   //特殊处理，商品编号就是等级ID
            var gradeExt = JsonHelper.ToObject<GradeExt>(grade.ext);

            CouponGift(order, gradeExt);
        }

        /// <summary>
        /// 补发佣金(每次调用都会补发)
        /// </summary>
        /// <param name="order_id"></param>
        [HttpGet]
        public void SendBrokerage(int order_id)
        {
            var order = orderSvc.Get(order_id);
            var user = userSvc.Get(order.user_id);
            AddBrokerage(order, user);
        }
        #endregion
    }
}  